/*
	flad : Copyright 2010 Dale J Williams

	Licensed under the Apache License, Version 2.0 (the "License");
	you may not use this file except in compliance with the License.
	You may obtain a copy of the License at

	http://www.apache.org/licenses/LICENSE-2.0

	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
*/
package lads.flad.scene {
	
	import flash.geom.Point;
	import lads.flad.flad;
	import lads.flad.interfaces.IGameObject;
	
	import lads.flad.GameCore;
	import lads.flad.GameEngine;
	import lads.flad.scene.GameScene;
	import lads.flad.utils.QuickMath;
	import flash.display.Sprite;
	import flash.geom.Rectangle;
	
	/**
	 * SceneObject: A base class for any instance of an object in the game scene.
	 * @author Dale J Williams
	 * @version 1.1
	 */
	public class SceneObject extends Sprite implements IGameObject {
		
		private var _scene			:GameScene;		
		private var _engine			:GameEngine;
		private var _core			:GameCore;
		private var _bounds			:Rectangle;
		private var _autoBounds		:Boolean;
		
		private var _onAwake		:Function;
		private var _onStart		:Function;
		private var _onUpdate		:Function;
		private var _isUpdate		:Boolean;
		private var _onStop			:Function;
		
		private var _ranBefore		:Boolean;
		
		protected var point			:Point;
		
		public function SceneObject(name:String) {
			this.name = name;
			onAwake = registerInbuilt("awake");
			onStart = registerInbuilt("start");
			onUpdate = registerInbuilt("update");
			onStop = registerInbuilt("stop");
		}
		
		private function registerInbuilt(name:String):Function {
			if (this.hasOwnProperty(name)) {
				if (this[name] is Function) {
					return this[name] as Function;
				} else throw new Error(name + " is reserved for an inbuilt function, please revise.");
			}
			return null;
		}
		
		public function getAsPoint():Point {
			if (!point) point = new Point();
			point.x = x;
			point.y = y;
			return point;
		}
		
		/// awake is called on first run, by start only
		private function _awake():void {
			if (_ranBefore) return;
			if (_onAwake == null) return;
			_onAwake();
			_ranBefore = true;
		}
		
		/// start is called when this is added to the map
		flad function _start():void {
			if (!_ranBefore) _awake();
			if (_onStart == null) return;
			_onStart();			
			_ranBefore = true;
		}
		
		/// stop is called when this is removed from the map
		flad function _stop():void {
			if (_onStop == null) return;
			_onStop();
		}
		
		/// update is called when this is added to the map
		flad function _update():void { 
			if (!_isUpdate) return;
			if (_autoBounds) _bounds = getBounds(_scene);
			_onUpdate();
		}
		
		/// map is a reference to the map, start or stop will be called when this is added to or removed from
		public function get scene():GameScene { return _scene; }		
		public function set scene(value:GameScene):void {
			_scene = value;
			_engine = value ? _scene.engine : null;
			_core = value ? _engine.core : null;
		}
		
		/// returns bounds, according to map dimensions
		public function get bounds():Rectangle {
			if (!_bounds) _bounds = getBounds(_scene);
			return _bounds; 
		}
		
		/// game is a reference to the game's core
		public function get core():GameCore { return _core; }
		
		public function get onAwake():Function { return _onAwake; }		
		public function set onAwake(value:Function):void {
			_onAwake = value;
		}
		
		public function get onStart():Function { return _onStart; }		
		public function set onStart(value:Function):void {
			_onStart = value;
		}
		
		public function get onUpdate():Function { return _onUpdate; }		
		public function set onUpdate(value:Function):void {
			_onUpdate = value;
			_isUpdate = value != null;
		}
		
		public function get onStop():Function { return _onStop; }		
		public function set onStop(value:Function):void {
			_onStop = value;
		}
		
		public function get autoBounds():Boolean { return _autoBounds; }		
		public function set autoBounds(value:Boolean):void {
			_autoBounds = value;
		}
		
		public function get ranBefore():Boolean { return _ranBefore; }
		
	}

}